From 76c82b0a7f6a62bf8db6871223242d1d0691fabf Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Wed, 30 Jun 2004 14:00:44 +0000 Subject: [PATCH] bitkeeper revision 1.1041.1.1 (40e2c78cfPsfEf6gMo2dzBk-JDH8iw) Fix refcnting on Xen heap pages mapped by guests. --- xen/common/dom0_ops.c | 4 +-- xen/common/domain.c | 69 ++++++++++++++++++++++++----------------- xen/common/keyhandler.c | 24 ++++++++++++-- xen/common/memory.c | 15 ++++----- xen/include/xen/mm.h | 8 +++-- xen/include/xen/sched.h | 9 +++--- 6 files changed, 84 insertions(+), 45 deletions(-) diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 83cc82f6ed..96d7197b3e 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -247,7 +247,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) { ret = 0; - spin_lock(&d->page_list_lock); + spin_lock(&d->page_alloc_lock); list_ent = d->page_list.next; for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ ) { @@ -261,7 +261,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) buffer++; list_ent = frame_table[pfn].list.next; } - spin_unlock(&d->page_list_lock); + spin_unlock(&d->page_alloc_lock); op->u.getmemlist.num_pfns = i; copy_to_user(u_dom0_op, op, sizeof(*op)); diff --git a/xen/common/domain.c b/xen/common/domain.c index f85b744304..5375a5de18 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -80,7 +80,7 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu) d->addr_limit = USER_DS; - spin_lock_init(&d->page_list_lock); + spin_lock_init(&d->page_alloc_lock); INIT_LIST_HEAD(&d->page_list); d->max_pages = d->tot_pages = 0; @@ -260,19 +260,19 @@ struct pfn_info *alloc_domain_page(struct domain *d) if ( d != NULL ) { wmb(); /* Domain pointer must be visible before updating refcnt. */ - spin_lock(&d->page_list_lock); + spin_lock(&d->page_alloc_lock); if ( unlikely(d->tot_pages >= d->max_pages) ) { DPRINTK("Over-allocation for domain %u: %u >= %u\n", d->domain, d->tot_pages, d->max_pages); - spin_unlock(&d->page_list_lock); + spin_unlock(&d->page_alloc_lock); goto free_and_exit; } list_add_tail(&page->list, &d->page_list); page->count_and_flags = PGC_allocated | 1; if ( unlikely(d->tot_pages++ == 0) ) get_domain(d); - spin_unlock(&d->page_list_lock); + spin_unlock(&d->page_alloc_lock); } return page; @@ -291,27 +291,33 @@ void free_domain_page(struct pfn_info *page) int drop_dom_ref; struct domain *d = page->u.domain; - /* Deallocation of such pages is handled out of band. */ if ( unlikely(IS_XEN_HEAP_FRAME(page)) ) - return; + { + spin_lock_recursive(&d->page_alloc_lock); + drop_dom_ref = (--d->xenheap_pages == 0); + spin_unlock_recursive(&d->page_alloc_lock); + } + else + { + page->tlbflush_timestamp = tlbflush_clock; + page->u.cpu_mask = 1 << d->processor; + + /* NB. May recursively lock from domain_relinquish_memory(). */ + spin_lock_recursive(&d->page_alloc_lock); + list_del(&page->list); + drop_dom_ref = (--d->tot_pages == 0); + spin_unlock_recursive(&d->page_alloc_lock); - page->tlbflush_timestamp = tlbflush_clock; - page->u.cpu_mask = 1 << d->processor; + page->count_and_flags = 0; + + spin_lock_irqsave(&free_list_lock, flags); + list_add(&page->list, &free_list); + free_pfns++; + spin_unlock_irqrestore(&free_list_lock, flags); + } - /* NB. May recursively lock from domain_relinquish_memory(). */ - spin_lock_recursive(&d->page_list_lock); - list_del(&page->list); - drop_dom_ref = (--d->tot_pages == 0); - spin_unlock_recursive(&d->page_list_lock); if ( drop_dom_ref ) put_domain(d); - - page->count_and_flags = 0; - - spin_lock_irqsave(&free_list_lock, flags); - list_add(&page->list, &free_list); - free_pfns++; - spin_unlock_irqrestore(&free_list_lock, flags); } @@ -337,8 +343,13 @@ void domain_relinquish_memory(struct domain *d) put_page_and_type(&frame_table[pagetable_val(d->mm.pagetable) >> PAGE_SHIFT]); + /* Relinquish Xen-heap pages. Currently this can only be 'shared_info'. */ + page = virt_to_page(d->shared_info); + if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) ) + put_page(page); + /* Relinquish all pages on the domain's allocation list. */ - spin_lock_recursive(&d->page_list_lock); /* may enter free_domain_page() */ + spin_lock_recursive(&d->page_alloc_lock); /* may enter free_domain_page */ list_for_each_safe ( ent, tmp, &d->page_list ) { page = list_entry(ent, struct pfn_info, list); @@ -367,7 +378,7 @@ void domain_relinquish_memory(struct domain *d) } while ( unlikely(y != x) ); } - spin_unlock_recursive(&d->page_list_lock); + spin_unlock_recursive(&d->page_alloc_lock); } @@ -774,11 +785,11 @@ int construct_dom0(struct domain *p, } /* Construct a frame-allocation list for the initial domain. */ - for ( pfn = (alloc_start>>PAGE_SHIFT); - pfn < (alloc_end>>PAGE_SHIFT); - pfn++ ) + for ( mfn = (alloc_start>>PAGE_SHIFT); + mfn < (alloc_end>>PAGE_SHIFT); + mfn++ ) { - page = &frame_table[pfn]; + page = &frame_table[mfn]; page->u.domain = p; page->type_and_flags = 0; page->count_and_flags = PGC_allocated | 1; @@ -890,9 +901,11 @@ int construct_dom0(struct domain *p, si->mfn_list = vphysmap_start; /* Write the phys->machine and machine->phys table entries. */ - for ( pfn = 0; pfn < p->tot_pages; pfn++ ) + for ( mfn = (alloc_start>>PAGE_SHIFT); + mfn < (alloc_end>>PAGE_SHIFT); + mfn++ ) { - mfn = (alloc_start >> PAGE_SHIFT) + pfn; + pfn = mfn - (alloc_start>>PAGE_SHIFT); ((unsigned long *)vphysmap_start)[pfn] = mfn; machine_to_phys_mapping[mfn] = pfn; } diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index 7365d5cb90..aff7ccfd1b 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -60,6 +60,8 @@ void do_task_queues(unsigned char key, void *dev_id, unsigned long flags; struct domain *d; s_time_t now = NOW(); + struct list_head *ent; + struct pfn_info *page; printk("'%c' pressed -> dumping task queues (now=0x%X:%08X)\n", key, (u32)(now>>32), (u32)now); @@ -68,10 +70,28 @@ void do_task_queues(unsigned char key, void *dev_id, for_each_domain ( d ) { - printk("Xen: DOM %u, CPU %d [has=%c] refcnt=%d nr_pages=%d\n", + printk("Xen: DOM %u, CPU %d [has=%c] refcnt=%d nr_pages=%d " + "xenheap_pages=%d\n", d->domain, d->processor, test_bit(DF_RUNNING, &d->flags) ? 'T':'F', - atomic_read(&d->refcnt), d->tot_pages); + atomic_read(&d->refcnt), d->tot_pages, d->xenheap_pages); + + if ( d->tot_pages < 10 ) + { + list_for_each ( ent, &d->page_list ) + { + page = list_entry(ent, struct pfn_info, list); + printk("Page %08x: caf=%08x, taf=%08x\n", + page_to_phys(page), page->count_and_flags, + page->type_and_flags); + } + } + + page = virt_to_page(d->shared_info); + printk("Shared_info@%08x: caf=%08x, taf=%08x\n", + page_to_phys(page), page->count_and_flags, + page->type_and_flags); + printk("Guest: upcall_pend = %02x, upcall_mask = %02x\n", d->shared_info->vcpu_data[0].evtchn_upcall_pending, d->shared_info->vcpu_data[0].evtchn_upcall_mask); diff --git a/xen/common/memory.c b/xen/common/memory.c index 4675a95d2e..d83d7111dc 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -907,17 +907,18 @@ static int do_extended_command(unsigned long ptr, unsigned long val) */ if ( d < e ) { - spin_lock(&d->page_list_lock); - spin_lock(&e->page_list_lock); + spin_lock(&d->page_alloc_lock); + spin_lock(&e->page_alloc_lock); } else { - spin_lock(&e->page_list_lock); - spin_lock(&d->page_list_lock); + spin_lock(&e->page_alloc_lock); + spin_lock(&d->page_alloc_lock); } /* A domain shouldn't have PGC_allocated pages when it is dying. */ - if ( unlikely(test_bit(DF_DYING, &e->flags)) ) + if ( unlikely(test_bit(DF_DYING, &e->flags)) || + unlikely(IS_XEN_HEAP_FRAME(page)) ) { okay = 0; goto reassign_fail; @@ -967,8 +968,8 @@ static int do_extended_command(unsigned long ptr, unsigned long val) list_add_tail(&page->list, &e->page_list); reassign_fail: - spin_unlock(&d->page_list_lock); - spin_unlock(&e->page_list_lock); + spin_unlock(&d->page_alloc_lock); + spin_unlock(&e->page_alloc_lock); break; case MMUEXT_RESET_SUBJECTDOM: diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index 4688037deb..c9eaae530a 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -91,11 +91,15 @@ struct pfn_info #define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \ do { \ (_pfn)->u.domain = (_dom); \ + /* The incremented type count is intended to pin to 'writeable'. */ \ + (_pfn)->type_and_flags = PGT_writeable_page | PGT_validated | 1; \ wmb(); /* install valid domain ptr before updating refcnt. */ \ + spin_lock(&(_dom)->page_alloc_lock); \ /* _dom holds an allocation reference */ \ (_pfn)->count_and_flags = PGC_allocated | 1; \ - /* The incremented type count is intended to pin to 'writeable'. */ \ - (_pfn)->type_and_flags = PGT_writeable_page | PGT_validated | 1; \ + if ( unlikely((_dom)->xenheap_pages++ == 0) ) \ + get_domain(_dom); \ + spin_unlock(&(_dom)->page_alloc_lock); \ } while ( 0 ) extern struct pfn_info *frame_table; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index fb4ab16ba3..009ce5f5e3 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -89,10 +89,11 @@ struct domain char name[MAX_DOMAIN_NAME]; s_time_t create_time; - spinlock_t page_list_lock; - struct list_head page_list; - unsigned int tot_pages; /* number of pages currently possesed */ - unsigned int max_pages; /* max number of pages that can be possesed */ + spinlock_t page_alloc_lock; /* protects all the following fields */ + struct list_head page_list; /* linked list, of size tot_pages */ + unsigned int tot_pages; /* number of pages currently possesed */ + unsigned int max_pages; /* maximum value for tot_pages */ + unsigned int xenheap_pages; /* # pages allocated from Xen heap */ /* Scheduling. */ struct list_head run_list; -- 2.30.2